package com.junmeng.libfloating.ball

import android.animation.LayoutTransition
import android.content.Context
import android.graphics.Color
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.HORIZONTAL
import androidx.viewpager2.widget.ViewPager2
import com.junmeng.lib.ui.draglayout.DirectChildDragableLayout
import com.junmeng.lib.ui.draglayout.DirectChildDragableLayout.ChildDragStatus.Companion.CHILD_DRAG_START
import com.junmeng.libfloating.R
import com.junmeng.libfloating.base.FloatingManager
import com.junmeng.libfloating.base.IFloatingViewFactory
import com.junmeng.libfloating.base.SingleDelayMainHandler
import com.junmeng.libfloating.tab.MenuEnterAppInfo
import com.junmeng.libfloating.tab.MenuEnterDevOptions
import com.junmeng.libfloating.tab.MenuMainThreadCrash
import com.junmeng.libfloating.tab.MenuWorkThreadCrash
import com.junmeng.libfloating.tab.TabLog
import com.junmeng.libfloating.tab.TabMenu
import com.junmeng.libfloating.util.Log
import com.junmeng.libfloating.util.ViewUtil

/**
 * 悬浮视图的一个例子，用户如有特殊需求，可以自己实现
 */
class SimpleFloatingViewFactory(private var builder: Builder) : IFloatingViewFactory {

    companion object {
        @JvmStatic
        fun newBuilder(): Builder {
            return Builder()
        }
    }

    class Builder {

        var ballConfigBuilder: BallConfig.Builder = BallConfig.newBuilder(this)
        var panelConfigBuilder: PanelConfig.Builder = PanelConfig.newBuilder(this)
        private var enablePanelSimpleTab: Boolean = false

        /**
         * 悬浮球的自定义配置
         */
        fun newBallConfig(): BallConfig.Builder {
            return ballConfigBuilder
        }

        /**
         * 悬浮面板的自定义配置
         */
        fun newPanelConfig(): PanelConfig.Builder {
            return panelConfigBuilder
        }

        /**
         * 是否启用内部的示例tab
         */
        fun enablePanelSimpleTab(enable: Boolean): Builder {
            enablePanelSimpleTab = enable
            return this
        }

        fun build(): SimpleFloatingViewFactory {
            if (enablePanelSimpleTab) {
                panelConfigBuilder.registerTab(
                    TabMenu.newBuilder()
//                        .registerItem(Menu0())
                        .registerItem(MenuEnterDevOptions())
                        .registerItem(MenuEnterAppInfo())
                        .registerItem(MenuMainThreadCrash())
                        .registerItem(MenuWorkThreadCrash())
                        .build()
                ).registerTab(TabLog())
            }
            return SimpleFloatingViewFactory(this)
        }
    }


    private lateinit var dragView: DirectChildDragableLayout

    private var childPanel: View? = null
    private lateinit var childBall: View


    private var tabsRecyclerView: RecyclerView? = null
    private var viewpagerView: ViewPager2? = null
    private val tabs: ArrayList<IPanelTab> = ArrayList()
    private var tabAdapter: TabAdapter? = null
    private var tabPanelAdapter: TabPanelAdapter? = null

    private lateinit var panelConfig: DirectChildDragableLayout.DirectChildDragConfig

    private var floatingBallId: String = "" //此view所在的悬浮球id,空表示未知

    private var singleDelayMainHandler: SingleDelayMainHandler = SingleDelayMainHandler()

    init {
        initDragView()
        initBallView()
        initPanelView()
    }

    private fun dpToPx(context: Context, dp: Float): Int {
        val density: Float = context.resources.displayMetrics.density
        return (dp * density + 0.5f).toInt()
    }

    private fun initDragView() {
        dragView = DirectChildDragableLayout(FloatingManager.application!!)
        dragView.setPadding(
            builder.ballConfigBuilder.marginLeft,
            builder.ballConfigBuilder.marginTop,
            builder.ballConfigBuilder.marginRight,
            builder.ballConfigBuilder.marginBottom
        )

        dragView.layoutTransition = LayoutTransition().apply {
            enableTransitionType(LayoutTransition.CHANGING)
        }//应用系统默认布局变换动画，但效果好像不好，暂时注释

        panelConfig = DirectChildDragableLayout.DirectChildDragConfig(
            R.id.floating_panel_root,
            true,
            false,
            false,
            builder.panelConfigBuilder.canDragOverEdge,
            true
        )
        dragView.addDirectChildDragConfig(DirectChildDragableLayout.DirectChildDragConfig().apply {
            targetChildViewId = R.id.floating_ball_root
            canDrag = true
            isAutoAdsorptionToHorizontalEdge = true
        })
        dragView.addDirectChildDragConfig(panelConfig)

        dragView.addChildAutoAdsorptionGravityListener(object :
            DirectChildDragableLayout.ChildAutoAdsorptionGravityListener {
            override fun onGravity(child: View, gravity: Int) {
                when (gravity) {
                    Gravity.LEFT -> {
                        if (child == childBall) {
                            child.setBackgroundResource(builder.ballConfigBuilder.backgroundSelector[0])
                            delayEnterIdle()
                        }
                    }

                    Gravity.RIGHT -> {
                        if (child == childBall) {
                            child.setBackgroundResource(builder.ballConfigBuilder.backgroundSelector[2])
                            delayEnterIdle()
                        }
                    }
                }
            }

        })
        dragView.addChildDragListener(object : DirectChildDragableLayout.ChildDragListener {
            override fun onDrag(child: View, status: Int) {
                if (CHILD_DRAG_START == status) {
                    if (child == childBall) {
                        singleDelayMainHandler.stop()
                        child.setBackgroundResource(builder.ballConfigBuilder.backgroundSelector[1])
                        child.alpha = 1f
                    }
                }
            }

        })
        dragView.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
            if (right - left != oldRight - oldLeft) {
                setPanelSizeLimit()
            }
        }
    }

    private fun initViewPager() {
        tabs.addAll(builder.panelConfigBuilder.tabs)
        tabsRecyclerView = childPanel?.findViewById(R.id.floating_tabs)
        viewpagerView = childPanel?.findViewById(R.id.floating_viewpager)

        tabsRecyclerView?.setBackgroundResource(builder.panelConfigBuilder.tabBarBackground)
        viewpagerView?.setBackgroundResource(builder.panelConfigBuilder.tabContentBackground)

        tabsRecyclerView?.layoutManager =
            LinearLayoutManager(FloatingManager.application, HORIZONTAL, false)

        tabAdapter = TabAdapter()
        tabsRecyclerView?.adapter = tabAdapter
        tabAdapter?.setOnItemClickListener(object : TabItemClickListener {
            override fun onItemClick(view: View, position: Int, item: String) {
                viewpagerView?.currentItem = position
            }
        })

        tabPanelAdapter = TabPanelAdapter()
        viewpagerView?.adapter = tabPanelAdapter

        viewpagerView?.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                tabAdapter?.setSelected(position)
                tabAdapter?.notifyDataSetChanged()
            }
        })
        viewpagerView?.currentItem = 0
    }

    private fun initBallView() {
        childBall = LayoutInflater.from(FloatingManager.application!!)
            .inflate(builder.ballConfigBuilder.layoutResId, dragView, false)

        childBall.findViewById<ImageView>(R.id.floating_ball_icon)
            .setImageResource(builder.ballConfigBuilder.iconResId)
        val lp = FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT
        )
        lp.gravity = builder.ballConfigBuilder.initGravity
        childBall.layoutParams = lp

        if (lp.gravity and Gravity.END == Gravity.END || lp.gravity and Gravity.RIGHT == Gravity.RIGHT) {
            childBall.setBackgroundResource(builder.ballConfigBuilder.backgroundSelector[2])
        } else {
            childBall.setBackgroundResource(builder.ballConfigBuilder.backgroundSelector[0])
        }

        childBall.setOnClickListener {
            showPanel()
        }

        dragView.addView(childBall)
    }


    private fun initPanelView() {
        childPanel = LayoutInflater.from(FloatingManager.application!!)
            .inflate(builder.panelConfigBuilder.layoutResId, dragView, false)

        val closeView = childPanel?.findViewById<ImageView>(R.id.floating_close)
        val returnView = childPanel?.findViewById<ImageView>(R.id.floating_return)
        val removeView = childPanel?.findViewById<ImageView>(R.id.floating_remove)
        val dingView = childPanel?.findViewById<ImageView>(R.id.floating_ding)
        val zoomInView = childPanel?.findViewById<ImageView>(R.id.floating_zoomin)
        val recoverView = childPanel?.findViewById<ImageView>(R.id.floating_recover)
        val zoomOutView = childPanel?.findViewById<ImageView>(R.id.floating_zoomout)
        if (builder.panelConfigBuilder.supportScale) {
            zoomInView?.visibility = View.VISIBLE
            recoverView?.visibility = View.VISIBLE
            zoomOutView?.visibility = View.VISIBLE
        } else {
            zoomInView?.visibility = View.GONE
            recoverView?.visibility = View.GONE
            zoomOutView?.visibility = View.GONE
        }
        recoverView?.setOnClickListener {
            childPanel?.scaleX = 1.0f
            childPanel?.scaleY = 1.0f
            updateDingViewStatus(dingView, true)
        }
        zoomInView?.setOnClickListener {
            childPanel?.scaleX?.let {
                childPanel?.scaleX = it * 1.1f
            }
            childPanel?.scaleY?.let {
                childPanel?.scaleY = it * 1.1f
            }
            updateDingViewStatus(dingView)
        }
        zoomOutView?.setOnClickListener {
            childPanel?.scaleX?.let {
                childPanel?.scaleX = it * 0.9f
            }
            childPanel?.scaleY?.let {
                childPanel?.scaleY = it * 0.9f
            }
            updateDingViewStatus(dingView)
        }

        dingView?.setOnClickListener {
            updateDingViewStatus(dingView)
        }

        closeView?.setOnClickListener {
            //全局隐藏
            AlertDialog.Builder(getContext(), R.style.floating_alertDialogStyle)
                .setMessage("关闭后将无法再显示此悬浮球，是否继续").setPositiveButton(
                    "确定"
                ) { dialog, which ->
//                    dragView.visibility = View.GONE
                    FloatingManager.getInstance().getFloatingBall(floatingBallId)?.let {
                        it.enable(false)
                    }
                }.setNegativeButton("取消", null).setCancelable(true).create().show()

        }
        returnView?.setOnClickListener {
            showBall()
        }
        removeView?.setOnClickListener {
            AlertDialog.Builder(getContext(), R.style.floating_alertDialogStyle)
                .setMessage("仅在此刻从当前Activity实例中移除此悬浮球，Activity重新可见后则悬浮球会被重新添加")
                .setPositiveButton(
                    "确定"
                ) { dialog, which ->
                    //只是在当前移除掉，下次进来依然会添加
                    ViewUtil.removeViewFromParent(dragView)
                }.setNegativeButton("取消", null).setCancelable(true).create().show()
        }
        initViewPager()

    }

    private fun updateDingViewStatus(dingView: ImageView?, isRecoverClick: Boolean = false) {
        dingView ?: return
        if (childPanel?.scaleX == 1.0f && childPanel?.scaleY == 1.0f) {
            if (dingView.isSelected) {
                dingView.isSelected = false
                dingView.setImageResource(builder.panelConfigBuilder.dingResIds[0])
                panelConfig.canDrag = true
            } else {
                if (!isRecoverClick) {
                    dingView.isSelected = true
                    dingView.setImageResource(builder.panelConfigBuilder.dingResIds[1])
                    panelConfig.canDrag = false
                }

            }
        } else {
            dingView.isSelected = true
            dingView.setImageResource(builder.panelConfigBuilder.dingResIds[1])
            panelConfig.canDrag = false
        }

    }

    /**
     * 展示面板
     */
    private fun showPanel() {

        setPanelSizeLimit()
//        childBall.alpha = 1.0f
        childBall?.let {
            ViewUtil.removeViewFromParent(it)
        }
        dragView?.let {
            childPanel?.let { panel ->
                ViewUtil.addView(it, panel)
            }
        }


    }

    /**
     * 面板尺寸约束
     */
    private fun setPanelSizeLimit() {
        Log.i("setPanelSizeLimit:dragView.measuredWidth=${dragView.measuredWidth},measuredHeight=${dragView.measuredHeight}")
        if (builder.panelConfigBuilder.widthRatio > 1) {
            childPanel?.layoutParams?.width = builder.panelConfigBuilder.widthRatio.toInt()
        } else {
            childPanel?.layoutParams?.width =
                ((dragView.measuredWidth - dragView.paddingStart - dragView.paddingEnd) * builder.panelConfigBuilder.widthRatio).toInt()
        }
        childPanel?.layoutParams = childPanel?.layoutParams

        if (viewpagerView?.layoutParams is ConstraintLayout.LayoutParams) {
            var lp = viewpagerView?.layoutParams as ConstraintLayout.LayoutParams
            if (builder.panelConfigBuilder.heightMaxRatio > 1) {
                lp?.matchConstraintMaxHeight = builder.panelConfigBuilder.heightMaxRatio.toInt()
            } else {
                val maxHeight =
                    ((dragView.measuredHeight - dragView.paddingTop - dragView.paddingBottom) * builder.panelConfigBuilder.heightMaxRatio).toInt()
                lp?.matchConstraintMaxHeight = maxHeight
            }
            viewpagerView?.layoutParams = lp

        }
    }

    /**
     * 展示悬浮球
     */
    private fun showBall() {
//        childBall.alpha = 1.0f

        dragView?.let {
            ViewUtil.addView(it, childBall)
        }
        childPanel?.let {
            ViewUtil.removeViewFromParent(it)
        }

        delayEnterIdle()
    }

    private fun delayEnterIdle() {
        singleDelayMainHandler.postDelayed({
            childBall.alpha = builder.ballConfigBuilder.idleAlpha
            (childBall.layoutParams as? FrameLayout.LayoutParams)?.apply {
                var delta = getDelta().toInt()
                if (gravity == Gravity.NO_GRAVITY || gravity == Gravity.LEFT || gravity == Gravity.START) {
                    if (leftMargin >= 0) {
                        leftMargin -= delta
                        childBall.layoutParams = this
                    }

                } else if (gravity == Gravity.RIGHT || gravity == Gravity.END) {
                    if (rightMargin >= 0) {
                        rightMargin -= delta
                        childBall.layoutParams = this
                    }

                }
            }
        }, builder.ballConfigBuilder.idleDelayMs)
    }

    private fun getDelta(): Float {
        if (builder.ballConfigBuilder.idleWidth > 1) {
            return childBall.width - builder.ballConfigBuilder.idleWidth
        } else if (builder.ballConfigBuilder.idleWidth > 0) {
            return (1.0f - builder.ballConfigBuilder.idleWidth) * childBall.width
        }
        return 0f
    }

    private fun getContext(): Context {
        return (dragView.parent as ViewGroup).context
    }

    override fun getView(): View {
        return dragView
    }

    override fun setAttachFloatingBallId(id: String) {
        this.floatingBallId = id
    }

    interface TabItemClickListener {
        fun onItemClick(view: View, position: Int, item: String)
    }

    inner class TabAdapter : RecyclerView.Adapter<TabAdapter.ViewHolder>() {
        var listener: TabItemClickListener? = null
        var selectedItemPosition: Int? = 0

        @ColorInt
        var selectedItemColor: Int = Color.WHITE
        var unselectedItemColor: Int = Color.GRAY

        fun setOnItemClickListener(listener: TabItemClickListener) {
            this.listener = listener
        }


        fun setSelected(pos: Int) {
            selectedItemPosition = pos
        }


        override fun onCreateViewHolder(
            parent: ViewGroup, viewType: Int
        ): ViewHolder {
            return ViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.floating_item_tab, parent, false)
            )
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val item = tabs[position]
            if (selectedItemPosition == position) {
                holder.textView.setTextColor(selectedItemColor)
            } else {
                holder.textView.setTextColor(unselectedItemColor)
            }
            holder.textView.text = item.getLabel()
            holder.itemView.setOnClickListener {
                listener?.onItemClick(it, position, item.getLabel())
            }
        }

        override fun getItemCount(): Int {
            return tabs.size
        }

        inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            var textView: TextView = itemView.findViewById(R.id.floating_tab_text)
        }

    }

    inner class TabPanelAdapter : RecyclerView.Adapter<TabPanelAdapter.ViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val resId = tabs[viewType].getLayoutResId()
            val view = LayoutInflater.from(parent.context).inflate(resId, parent, false)
            return ViewHolder(view)
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            tabs[position].onInitView(holder.itemView)
        }

        override fun getItemViewType(position: Int): Int {
            return position
        }

        override fun getItemCount(): Int {
            return tabs.size
        }

        inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {}
    }

    override fun getType(): String {
        return "topview_simple_floating"
    }

    override fun onCreateView(parent: ViewGroup, inflater: LayoutInflater): View {
        return getView()
    }

//    override fun getContainerView(decorView: View): ViewGroup {
//        return decorView.findViewById(android.R.id.content)
//    }

    override fun onAddIntoContainerView(parent: ViewGroup, child: View) {
        super.onAddIntoContainerView(parent, child)
    }
}